package com.huayu.languo.common.configurer;

import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;

@Configuration
public class TxAnoConfig {

    /**
     * 可传播事务配置
     */
    private static final String[] DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES =
                    {"add*", "save*", "insert*", "delete*", "update*", "edit*", "batch*", "create*", "remove*",};

    /**
     * 默认的只读事务
     */
    private static final String[] DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES = {"get*", "count*", "find*", "query*", "select*", "list*", "*",};


    /**
     * 声明式事务-拦截类型
     */
    @Bean("txSource")
    public TransactionAttributeSource transactionAttributeSource() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        /**
         * 只读事务 SUPPORTED，不做更新操作
         */
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        /**
         * 当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务 REQUIRED
         */
        RuleBasedTransactionAttribute requiredTx =
                        new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);


        // 默认的只读事务配置
        for (String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
            source.addTransactionalMethod(methodName, readOnlyTx);
        }
        // 默认的传播事务配置
        for (String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
            source.addTransactionalMethod(methodName, requiredTx);
        }
        // Map<String, TransactionAttribute> txMap = new HashMap<>();
        // txMap.put("add*", requiredTx);
        // source.setNameMap(txMap);

        return source;
    }

    /**
     * 切面拦截规则 参数会自动从容器中注入
     */
    @Bean
    public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) {
        AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();
        pointcutAdvisor.setAdvice(txInterceptor);
        pointcutAdvisor.setExpression("execution (* com.huayu.languo.biz.service.*.*(..))");
        return pointcutAdvisor;
    }

    /**
     * 事务拦截器
     */
    @Bean("txInterceptor")
    TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager transactionManager) {
        return new TransactionInterceptor(transactionManager, transactionAttributeSource());
    }
}
